from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator
from .snmp_utils import SNMPClient
from django.core.exceptions import ValidationError
from datetime import datetime
from django.utils import timezone

class Server(models.Model):
    name = models.CharField(max_length=100, verbose_name='服务器名称')
    ip_address = models.GenericIPAddressField(verbose_name='IP地址')
    status = models.BooleanField(default=True, verbose_name='状态')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    last_check = models.DateTimeField(auto_now=True, verbose_name='最后检查时间')
    cabinet = models.ForeignKey(
        'Cabinet', 
        on_delete=models.CASCADE, 
        related_name='servers', 
        verbose_name='所属机柜',
        null=True,
        blank=True
    )
    height = models.IntegerField('高度单位(U)', default=1)

    def __str__(self):
        return f"Server in {self.cabinet.number} at height {self.height}"

    class Meta:
        verbose_name = '服务器'
        verbose_name_plural = '服务器列表'

class MonitorLog(models.Model):
    server = models.ForeignKey(Server, on_delete=models.CASCADE, verbose_name='服务器')
    cpu_usage = models.FloatField(verbose_name='CPU使用率')
    memory_usage = models.FloatField(verbose_name='内存使用率')
    disk_usage = models.FloatField(verbose_name='磁盘使用率')
    timestamp = models.DateTimeField(auto_now_add=True, verbose_name='记录时间')

    class Meta:
        verbose_name = '监控日志'
        verbose_name_plural = '监控日志列表'

class Host(models.Model):
    MONITOR_TYPE_CHOICES = [
        ('ipmi', 'IPMI'),
        ('ssh', 'SSH'),
        ('snmp', 'SNMP'),
    ]
    
    STATUS_CHOICES = [
        ('enabled', '启用'),
        ('disabled', '禁用'),
        ('error', '错误'),
    ]
    
    hostname = models.CharField('主机名', max_length=255)
    ip_address = models.GenericIPAddressField(
        'IP地址', 
        unique=True,
        null=True,
        blank=True
    )
    monitor_type = models.CharField(
        '监控类型', 
        max_length=10, 
        choices=MONITOR_TYPE_CHOICES,
        default='ssh'
    )
    credentials = models.JSONField('认证信息', default=dict)
    status = models.CharField('状态', max_length=10, choices=STATUS_CHOICES, default='enabled')
    
    # 监控数据
    cpu_usage = models.FloatField(
        'CPU使用率',
        validators=[MinValueValidator(0), MaxValueValidator(100)],
        default=0
    )
    memory_usage = models.FloatField(
        '内存使用率',
        validators=[MinValueValidator(0), MaxValueValidator(100)],
        default=0
    )
    disk_usage = models.FloatField(
        '硬盘使用率',
        validators=[MinValueValidator(0), MaxValueValidator(100)],
        default=0
    )
    
    last_check = models.DateTimeField('最后检查时间', null=True, blank=True)
    created_at = models.DateTimeField('创建时间', auto_now_add=True)
    updated_at = models.DateTimeField('更新时间', auto_now=True)

    # SNMP相关字段
    snmp_port = models.IntegerField('SNMP端口', default=161)
    snmp_version = models.CharField('SNMP版本', max_length=10, default='2c')
    snmp_cpu_usage = models.FloatField('CPU使用率', null=True, blank=True)
    snmp_memory_usage = models.FloatField('内存使用率', null=True, blank=True)
    snmp_disk_usage = models.FloatField('磁盘使用率', null=True, blank=True)
    snmp_last_update = models.DateTimeField('最后更新时间', null=True, blank=True)

    # IPMI相关字段
    ipmi_username = models.CharField(max_length=50, null=True, blank=True, verbose_name='IPMI用户名')
    ipmi_password = models.CharField(max_length=50, null=True, blank=True, verbose_name='IPMI密码')
    temperature = models.FloatField(null=True, blank=True, verbose_name='温度')
    power_status = models.BooleanField(default=False, verbose_name='电源状态')
    fan_speed = models.FloatField(null=True, blank=True, verbose_name='风扇转速')

    class Meta:
        verbose_name = '主机'
        verbose_name_plural = '主机列表'
        ordering = ['hostname']

    def __str__(self):
        return f"{self.hostname} ({self.ip_address or '无IP'})"

    def get_credentials(self):
        """根据监控类型返回适当的认证信息"""
        if self.monitor_type == 'snmp':
            return {
                'community': self.credentials.get('community', 'public'),
                'version': self.credentials.get('version', '2c'),
            }
        else:
            return {
                'username': self.credentials.get('username', ''),
                'password': self.credentials.get('password', ''),
            }

    def update_snmp_metrics(self):
        """更新SNMP监控指标"""
        if self.monitor_type != 'snmp':
            return False

        try:
            # 从credentials中获取SNMP配置
            snmp_config = self.credentials or {}
            community = snmp_config.get('community', 'public')

            client = SNMPClient(
                host=self.ip_address,
                community=community,
                port=self.snmp_port,
                version=self.snmp_version
            )

            # 测试连接
            if not client.test_connection():
                raise ValidationError('SNMP连接失败，请检查配置和网络连接')

            # 获取系统指标
            metrics = client.get_metrics()

            # 更新数据
            self.snmp_cpu_usage = metrics['cpu_usage']
            self.snmp_memory_usage = metrics['memory_usage']
            self.snmp_disk_usage = metrics['disk_usage']
            self.snmp_last_update = metrics['timestamp']
            self.status = 'enabled'  # 更新成功，设置状态为启用
            self.save()

            return True

        except Exception as e:
            self.status = 'error'
            self.save()
            raise ValidationError(f'SNMP监控失败: {str(e)}')

class Alert(models.Model):
    LEVEL_CHOICES = [
        ('严重', '严重'),
        ('紧急', '紧急'),
        ('告警', '告警'),
        ('一般', '一般'),
    ]
    
    STATUS_CHOICES = [
        ('pending', '待处理'),
        ('confirmed', '已确认'),
        ('ignored', '已忽略'),
    ]
    
    host = models.ForeignKey(Host, on_delete=models.CASCADE, verbose_name='主机')
    level = models.CharField('级别', max_length=20, choices=LEVEL_CHOICES)
    description = models.TextField('描述')
    status = models.CharField('状态', max_length=20, choices=STATUS_CHOICES, default='pending')
    created_at = models.DateTimeField('创建时间', auto_now_add=True)
    updated_at = models.DateTimeField('更新时间', auto_now=True)

    class Meta:
        verbose_name = '告警'
        verbose_name_plural = verbose_name

    def __str__(self):
        return f"{self.host.hostname} - {self.level} - {self.created_at}"

class NetworkDevice(models.Model):
    DEVICE_TYPE_CHOICES = [
        ('router', '路由器'),
        ('switch', '交换机'),
        ('firewall', '防火墙'),
        ('other', '其他'),
    ]
    
    STATUS_CHOICES = [
        ('enabled', '启用'),
        ('disabled', '禁用'),
    ]
    
    name = models.CharField('设备名称', max_length=100)
    ip_address = models.GenericIPAddressField('IP地址')
    device_type = models.CharField('设备类型', max_length=20, choices=DEVICE_TYPE_CHOICES)
    snmp_community = models.CharField('SNMP团体名', max_length=50, default='public')
    snmp_port = models.IntegerField('SNMP端口', default=161)
    status = models.CharField('状态', max_length=20, choices=STATUS_CHOICES, default='enabled')
    
    # SNMP监控数据
    snmp_cpu_usage = models.FloatField('CPU使用率', null=True, blank=True)
    snmp_memory_usage = models.FloatField('内存使用率', null=True, blank=True)
    snmp_last_update = models.DateTimeField('最后更新时间', null=True, blank=True)
    
    created_at = models.DateTimeField('创建时间', auto_now_add=True)
    updated_at = models.DateTimeField('更新时间', auto_now=True)
    
    class Meta:
        verbose_name = '网络设备'
        verbose_name_plural = '网络设备'
        
    def __str__(self):
        return f"{self.name} ({self.ip_address})"
    
    def update_snmp_metrics(self):
        """更新SNMP监控数据"""
        if self.status != 'enabled':
            return
            
        try:
            client = SNMPClient(
                host=self.ip_address,
                community=self.snmp_community,
                port=self.snmp_port
            )
            
            metrics = client.get_metrics()
            
            self.snmp_cpu_usage = metrics.get('cpu_usage')
            self.snmp_memory_usage = metrics.get('memory_usage')
            self.snmp_last_update = datetime.now()
            self.save()
            
        except Exception as e:
            # 记录错误但不抛出异常
            print(f"更新SNMP指标失败: {str(e)}")

class IDC(models.Model):
    name = models.CharField('机房名称', max_length=100)
    location = models.CharField('位置', max_length=200)
    description = models.TextField('描述', blank=True)
    created_at = models.DateTimeField('创建时间', auto_now_add=True)
    updated_at = models.DateTimeField('更新时间', auto_now=True)

    class Meta:
        verbose_name = '机房'
        verbose_name_plural = '机房'

    def __str__(self):
        return self.name

class Rack(models.Model):
    STATUS_CHOICES = [
        ('normal', '正常'),
        ('warning', '警告'),
        ('error', '错误'),
        ('maintenance', '维护中'),
    ]
    
    idc = models.ForeignKey(IDC, on_delete=models.CASCADE, verbose_name='所属机房')
    name = models.CharField('机柜名称', max_length=50)
    position = models.CharField('位置编号', max_length=50)
    capacity = models.IntegerField('容量(U)', default=42)
    power_capacity = models.IntegerField('电力容量(W)', default=2000)
    x_position = models.FloatField('X坐标', help_text='3D展示用X坐标')
    y_position = models.FloatField('Y坐标', help_text='3D展示用Y坐标')
    status = models.CharField('状态', max_length=20, choices=STATUS_CHOICES, default='normal')
    temperature = models.FloatField('温度', default=25.0)
    humidity = models.FloatField('湿度', default=45.0)
    power_usage = models.FloatField('当前功率(W)', default=0)
    used_units = models.IntegerField('已使用U数', default=0)
    created_at = models.DateTimeField('创建时间', auto_now_add=True)
    updated_at = models.DateTimeField('更新时间', auto_now=True)
    
    class Meta:
        verbose_name = '机柜'
        verbose_name_plural = '机柜'

    def __str__(self):
        return f"{self.idc.name}-{self.name}"
    
    def get_status_color(self):
        status_colors = {
            'normal': '#00ff00',
            'warning': '#ffff00',
            'error': '#ff0000',
            'maintenance': '#0000ff',
        }
        return status_colors.get(self.status, '#666666')
    
    def get_usage_percentage(self):
        return (self.used_units / self.capacity) * 100 if self.capacity else 0
    
    def get_power_percentage(self):
        return (self.power_usage / self.power_capacity) * 100 if self.power_capacity else 0

class AssetCategory(models.Model):
    """资产分类"""
    name = models.CharField('分类名称', max_length=50)
    description = models.TextField('描述', blank=True)

    class Meta:
        verbose_name = '资产分类'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

class Asset(models.Model):
    """资产模型"""
    STATUS_CHOICES = [
        ('in_use', '使用中'),
        ('idle', '闲置'),
        ('maintenance', '维修中'),
        ('scrapped', '已报废')
    ]

    name = models.CharField('资产名称', max_length=100)
    asset_number = models.CharField('资产编号', max_length=50, unique=True)
    category = models.ForeignKey(AssetCategory, on_delete=models.PROTECT, verbose_name='资产分类')
    specification = models.CharField('规格型号(U的大小)', max_length=100, blank=True)
    status = models.CharField('状态', max_length=20, choices=STATUS_CHOICES, default='in_use')
    purchase_date = models.DateField('购买日期', null=True, blank=True)
    warranty_period = models.IntegerField('保修期(月)', null=True, blank=True)
    location = models.CharField('存放位置', max_length=100, blank=True)
    up_rack_time = models.DateField('上架日期', null=True, blank=True)
    responsible_person = models.ForeignKey(
        'ResponsiblePerson', 
        on_delete=models.PROTECT, 
        verbose_name='负责人',
        null=True,
        blank=True
    )
    notes = models.TextField('备注', blank=True)
    created_at = models.DateTimeField('创建时间', auto_now_add=True)
    updated_at = models.DateTimeField('更新时间', auto_now=True)

    class Meta:
        verbose_name = '资产'
        verbose_name_plural = '资产'
        ordering = ['-created_at']

    def __str__(self):
        return f"{self.asset_number} - {self.name}"

class DeviceType(models.Model):
    """设备类型模型"""
    name = models.CharField('类型名称', max_length=50)
    description = models.TextField(
        '描述', 
        blank=True,
        null=True,
        default=''
    )
    code = models.CharField(
        '类型代码', 
        max_length=20, 
        unique=True,
        null=True,
        blank=True
    )
    
    class Meta:
        verbose_name = '设备类型'
        verbose_name_plural = verbose_name
        ordering = ['name']

    def __str__(self):
        return self.name

class Device(models.Model):
    """设备基础模型"""
    name = models.CharField('设备名称', max_length=100)
    device_type = models.ForeignKey(
        DeviceType,
        on_delete=models.PROTECT,
        verbose_name='设备类型',
        related_name='devices',
        null=True,  # 允许为空
        blank=True  # 允许在表单中为空
    )
    status = models.BooleanField('状态', default=True)
    description = models.TextField(
        '描述', 
        blank=True,
        null=True,
        default=''
    )
    created_at = models.DateTimeField('创建时间', auto_now_add=True)
    updated_at = models.DateTimeField('更新时间', auto_now=True)

    class Meta:
        verbose_name = '设备'
        verbose_name_plural = '设备列表'

    def __str__(self):
        return self.name

class Connection(models.Model):
    LINK_TYPES = [
        ('fiber', '光纤'),
        ('copper', '网线'),
    ]
    
    source = models.ForeignKey(
        Device,  # 改为使用 Device 模型
        on_delete=models.CASCADE, 
        related_name='source_connections',
        verbose_name='源设备'
    )
    target = models.ForeignKey(
        Device,  # 改为使用 Device 模型
        on_delete=models.CASCADE, 
        related_name='target_connections',
        verbose_name='目标设备'
    )
    link_type = models.CharField('连接类型', max_length=20, choices=LINK_TYPES)
    status = models.BooleanField('状态', default=True)
    
    class Meta:
        verbose_name = '设备连接'
        verbose_name_plural = verbose_name
    
    def __str__(self):
        return f'{self.source.name} -> {self.target.name}'

class ResponsiblePerson(models.Model):
    """负责人模型"""
    name = models.CharField('姓名', max_length=50)
    phone = models.CharField('联系电话', max_length=20)
    email = models.EmailField('邮箱', blank=True)
    department = models.CharField('部门', max_length=50)
    created_at = models.DateTimeField('创建时间', auto_now_add=True)

    class Meta:
        verbose_name = '负责人'
        verbose_name_plural = verbose_name

    def __str__(self):
        return f"{self.name} - {self.department}"

class AlertNotification(models.Model):
    """告警通知配置模型"""
    TYPE_CHOICES = [
        ('email', '邮件'),
        ('sms', '短信'),
        ('webhook', 'Webhook'),
        ('dingtalk', '钉钉'),
        ('feishu', '飞书'),
        ('serverchan', 'Server酱'),
        ('wecom', '企业微信'),
        ('telegram', 'Telegram'),
    ]

    name = models.CharField('名称', max_length=100)
    type = models.CharField('通知类型', max_length=20, choices=TYPE_CHOICES)
    alert_levels = models.JSONField('告警级别', default=list)
    config = models.JSONField('配置', default=dict)
    is_active = models.BooleanField('是否启用', default=True)
    created_at = models.DateTimeField('创建时间', auto_now_add=True)
    updated_at = models.DateTimeField('更新时间', auto_now=True)

    class Meta:
        verbose_name = '告警通知'
        verbose_name_plural = verbose_name
        ordering = ['-created_at']

    def __str__(self):
        return f"{self.name} ({self.get_type_display()})"

    def get_recipients(self):
        """获取接收人"""
        if self.type == 'email':
            return ', '.join(self.config.get('recipients', []))
        elif self.type == 'sms':
            return ', '.join(self.config.get('phone_numbers', []))
        elif self.type == 'dingtalk':
            return self.config.get('webhook_url', '')
        elif self.type == 'feishu':
            return self.config.get('webhook_url', '')
        elif self.type == 'serverchan':
            return self.config.get('send_key', '')
        elif self.type == 'wecom':
            return f"{self.config.get('corp_id', '')} - {self.config.get('agent_id', '')}"
        elif self.type == 'telegram':
            return f"{self.config.get('chat_id', '')}"
        elif self.type == 'webhook':
            return self.config.get('url', '')
        return ''

    @property
    def recipients(self):
        return self.get_recipients()

class Cabinet(models.Model):
    idc = models.ForeignKey(
        IDC, 
        on_delete=models.CASCADE, 
        related_name='cabinets',
        verbose_name='所属机房'
    )
    number = models.CharField(max_length=10)  # 机柜编号
    x_position = models.IntegerField()        # X坐标位置
    z_position = models.IntegerField()        # Z坐标位置
    # ... 其他机柜相关字段 ...

    class Meta:
        verbose_name = '机柜'
        verbose_name_plural = '机柜'

    def __str__(self):
        return self.number

class Switchboard(models.Model):
    cabinet = models.ForeignKey(
        Cabinet, 
        on_delete=models.CASCADE,
        related_name='switchboards',
        verbose_name='所属机柜'
    )
    height = models.IntegerField()  # 交换机在机柜中的高度位置
    # ... 其他交换机相关字段 ...

    class Meta:
        verbose_name = '交换机'
        verbose_name_plural = '交换机'

    def __str__(self):
        return f"Switchboard in {self.cabinet.number} at height {self.height}"

# 如果需要查看现有 Rack 模型的结构，可以使用以下命令：
# python manage.py inspectdb monitor_rack 